package chen.web.user;

import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;



public class EventConfigUtils {
	
	private static final String EventNode = "event";
	private static final String AllowNode = "allow";
	private static final String RoleNode = "role";
	private static final String PropertiesNode = "properties";
	private static final String EntryNode = "entry";
	private static final String KeyNode = "key";
	
	private Document doc = null;
	private Map<Role, Set<String>> allowMethodTypesMapping  = new HashMap<Role, Set<String>>();
	private Map<String, Map<String, String>> eventPropertiesMapping = new HashMap<String, Map<String, String>>();
	
	private EventConfigUtils(String configFilePath){
		URI uri = URI.create(configFilePath);
		if(uri.isAbsolute()){
			throw new IllegalArgumentException();
		}
		doc = loadDocument(configFilePath);
	}
	
	private static final Map<String, EventConfigUtils> InstanceMapping = new HashMap<String, EventConfigUtils>();
	public static EventConfigUtils getInstance(String configFilePath){
		EventConfigUtils utils = InstanceMapping.get(configFilePath);
		if(utils == null){
			utils = new EventConfigUtils(configFilePath);
			InstanceMapping.put(configFilePath, utils);
		}
		return utils;
	}
	
	public Set<String> getAllowMethdEventTypes(Role role){
		Set<String> methodTypes = allowMethodTypesMapping.get(role);
		if(methodTypes == null){
			methodTypes = loadAllowMethdEventTypes(role);
			allowMethodTypesMapping.put(role, methodTypes);
		}
		return methodTypes;
	}
	
	public Map<String, String> getEventProperties(String eventType){
		Map<String, String> eventProperties = eventPropertiesMapping.get(eventType);
		if(eventProperties == null){
			eventProperties = loadMethdEventProperties(eventType);
			eventPropertiesMapping.put(eventType, eventProperties);
		}
		return eventProperties;
	}
	
	public void saveEventConfig(String eventType, Map<String, String> config){
		
	}

	private synchronized Document loadDocument(String configFilePath){
		Document document = null;
		SAXReader saxReader = new SAXReader();
		try {
			document = saxReader.read(configFilePath);
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}
		return document;
	}
	
	private synchronized void storeDocument(Document doc, String configFilePath){
        OutputFormat format = OutputFormat.createPrettyPrint(); // 设置XML文档输出格式
		try {
			XMLWriter writer = new XMLWriter(new FileWriter(configFilePath), format);
			writer.write(doc);
			writer.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}
	}
	
	private synchronized Set<String> loadAllowMethdEventTypes(Role role){
		Set<String> eventTypes = new HashSet<String>();
		List<Element> eventElems = doc.getRootElement().elements(EventNode);
		for(Element eventElem : eventElems){
			String eventId = eventElem.attribute("id").getText();
			List<Element> roleElems = eventElem.element(AllowNode).elements(RoleNode);
			for(Element roleElem : roleElems){
				String roleId = roleElem.attribute("id").getText();
				if(role.getId() == Integer.parseInt(roleId)){
					eventTypes.add(eventId);
				}
			}
		}
		return eventTypes;
	}
	
	private synchronized Map<String, String> loadMethdEventProperties(String eventType){
		Map<String, String> properties = new HashMap<String, String>();
		Element eventElem = doc.elementByID(eventType);
		List<Element> entryElems = eventElem.element(PropertiesNode).elements(EntryNode);
		for(Element entryElem : entryElems){
			String key = entryElem.attribute(KeyNode).getText();
			String value = entryElem.getText();
			properties.put(key, value);
		}
		return properties;
	}
}
